

#include <iostream>
#include <typeinfo>
#include <string>
#include <cassert>
#include <any>


class Any
{
private:
    class holder 
    {
    public:
        virtual const std::type_info& type() = 0;
        virtual holder* clone() = 0;
        virtual ~holder() {}
    };

    template<class T>
    class placeholder : public holder
    {
    public:
        placeholder(const T& val) : _val(val) {}

        virtual const std::type_info& type() override
        {
            return typeid(T);
        }

        virtual holder* clone() override
        {
            placeholder* newholder = new placeholder(_val);
            return newholder;
        }

        T _val;
    };

    Any& swap(Any& other)
    {
        std::swap(_content, other._content);
        return *this;
    }

public:
    Any() : _content(nullptr) {}

    template<class T>
    Any(const T& val) : _content(new placeholder<T>(val)) {}

    Any(const Any& other) : _content(other._content ? other._content->clone() : nullptr) {}

    template<class T>
    T* getValPtr()
    {
        assert(typeid(T) == _content->type());
        return &(((placeholder<T>*)_content)->_val);
    }

    template<class T>
    Any& operator=(const T& val)
    {
        Any(val).swap(*this);
        return *this;
    }

    template<class T>
    Any& operator=(const Any& other)
    {
        Any(other).swap(*this);
        return *this;
    }

    ~Any() { if (_content) delete _content; }

private:
    holder* _content;
};

class Test
{
public:
    Test()
    {
        std::cout << "Test()" << std::endl;
    }

    Test(const Test& t)
    {
        std::cout << "Test(const Test& t)" << std::endl;
    }

    ~Test()
    {
        std::cout << "~Test()" << std::endl;
    }
};

int main()
{
    std::any a;
    a = 20;
    int* pi = std::any_cast<int>(&a);
    std::cout << *pi << std::endl;

    a = std::string("leihou");
    std::string* ps = std::any_cast<std::string>(&a);
    std::cout << *ps << std::endl;

    // Any a;
    // a = 10;
    // std::cout << *(a.getValPtr<int>()) << std::endl;
    // a = std::string("nihao");
    // std::cout << *(a.getValPtr<std::string>()) << std::endl;

    // a = Test();

    return 0;
}